using System.Reflection;
using Aurora.TaskScheduler.Abstractions;
using Aurora.TaskScheduler.Abstractions.Attributes;
using Aurora.TaskScheduler.Abstractions.BaseModel;
using Aurora.TaskScheduler.Abstractions.Message;
using Aurora.TaskScheduler.Abstractions.Storage;
using Aurora.TaskScheduler.Extension.Internel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;

namespace Aurora.TaskScheduler.Extension.BaseJobs;

/// <summary>
/// 当前项目程序集的定时任务
/// </summary>
public class ClassLibraryJob : IJob
{
    private readonly ILogger<ClassLibraryJob> _logger;
    private readonly IDataStorage _storage;
    private readonly IServiceScopeFactory _serviceProvider;
    private readonly ITaskHandler _taskHandler;
    private readonly TaskSchedulerOptions _options;

    public ClassLibraryJob(ILogger<ClassLibraryJob> logger, IDataStorage storage,
        IServiceScopeFactory serviceProvider, ITaskHandler taskHandler, IOptions<TaskSchedulerOptions> options)
    {
        _logger = logger;
        _storage = storage;
        _serviceProvider = serviceProvider;
        _taskHandler = taskHandler;
        _options = options.Value;
    }

    public async Task Execute(IJobExecutionContext context)
    {
        DateTime dateTime = DateTime.Now;
        AbstractTrigger trigger = (context as JobExecutionContextImpl).Trigger as AbstractTrigger;
        AppTask task = await _storage.GetTaskByName(trigger!.JobName, trigger.JobGroup);
        //估计是为了异步等待吧
        if (task == null)
        {
            task = await _storage.GetTaskByName(trigger.JobName, trigger.JobGroup);
        }

        if (task == null)
        {
            _logger.LogError($"组别:{trigger.Group},名称:{trigger.Name},的作业未找到,可能已被移除");
            return;
        }

        _logger.LogTrace(
            $"组别:{trigger.Group},名称:{trigger.Name},的作业开始执行,时间:{DateTime.Now:yyyy-MM-dd HH:mm:sss}");
        var appTaskLog = new AppTaskLog()
        {
            TaskId = task.Id,
            TaskName = task.TaskName,
            GroupName = task.GroupName,
            BeginDate = dateTime,
        };
        if (string.IsNullOrEmpty(task.DllClassName))
        {
            _logger.LogError(
                $"组别:{trigger.Group},名称:{trigger.Name},类名不能为空!,时间:{DateTime.Now:yyyy-MM-dd HH:mm:sss}");
            return;
        }

        var executeResult = await ExecuteAsync(task);
        appTaskLog.EndDate = DateTime.Now;
        appTaskLog.Msg = executeResult.message;
        appTaskLog.CreateTime = DateTime.Now;
        appTaskLog.ElapsedMilliseconds =
            (long)(appTaskLog.EndDate.Value - appTaskLog.BeginDate.Value).TotalMilliseconds;
        appTaskLog.Success = executeResult.success;
        appTaskLog.Id = Guid.NewGuid().ToString().Replace("-", "");
        await _storage.AddLog(appTaskLog);
        task.LastRunTime = DateTime.Now;
        await _storage.Update(task);
        if (task.TaskExecuteType.Equals("ONE"))
        {
            // 需要进行删除任务
            await _taskHandler.Remove(task);
        }
    }

    /// <summary>
    /// 执行方法
    /// </summary>
    /// <param name="task"></param>
    /// <returns></returns>
    private async Task<(bool success, string message)> ExecuteAsync(AppTask task)
    {
        string message = string.Empty;
        bool success = true;
        var scope = _serviceProvider.CreateScope();
        var type = ArgumentTypeExtension.Get(task.DllClassName);
        if (type == null) { 
            message="未找到任务执行的具体方法,类型："+task.DllClassName;
            success = false;
            return (success, message);
        }
        var makeGenericType = typeof(ITaskJob<>).MakeGenericType(type);
        var services = scope.ServiceProvider.GetServices(makeGenericType);
        var service = services.FirstOrDefault(x => x != null && x.GetType().Name.Equals(task.DllClassName));
        ITaskDistributeLock taskLockService = null;
        bool useTaskLock = false;
        try
        {
            if (service == null)
            {
                message = "未找到对应类型,请检查是否注入!，类型：" + task.DllClassName;
                success = false;
                return (success, message);
            }

            // 判断是否要使用分布式锁
            if (_options.UseTaskLock)
            {
                taskLockService = scope.ServiceProvider.GetService<ITaskDistributeLock>();
                var taskJobLockAttribute = service.GetType().GetCustomAttribute<TaskJobLockAttribute>();
                if (taskJobLockAttribute != null && taskLockService != null)
                {
                    var lockResult = await taskLockService.TryLockAsync(task.Id, taskJobLockAttribute.Timeout);
                    if (!lockResult)
                    {
                        message = "获取分布式锁失败，判断另一个相同的任务实例正在执行！类型：" + task.DllClassName;
                        success = false;
                        return (success, message);
                    }
                    else
                    {
                        useTaskLock = true;
                    }
                }
            }

            var methodInfo = service.GetType().GetMethod("ExecuteAsync");
            if (methodInfo == null)
            {
                message = "未找到对应的方法,请检查是否注入!，类型：" + task.DllClassName;
                success = false;
                return (success, message);
            }

            object param;
            if (type.IsValueType)
            {
                param = Convert.ChangeType(task.ApiParameter, type);
            }
            else if (typeof(string) == type)
            {
                param = task.ApiParameter;
            }
            else
            {
                param = JsonConvert.DeserializeObject(task.ApiParameter, type);
            }

            var result = await ((Task<JobResult>)methodInfo.Invoke(service, [param]))
                .ConfigureAwait(false);
            success = result.Success;
            message += result.Message;
        }
        catch (Exception e)
        {
            message += e.Message;
            success = false;
        }
        finally
        {
            // 判断是否要使用分布式锁
            if (taskLockService != null && useTaskLock)
            {
                await taskLockService.TryUnlockAsync(task.Id);
            }
        }

        return (success, message);
    }
}